#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h>
using namespace std;
const int gdefalult = 5; // 阻塞队列大小
// 阻塞队列
template <class T>
class Block_Queue
{
private:
    bool Isfull() { return _capacity == _block_queue.size(); }
    bool Isempty() { return _block_queue.empty(); }

public:
    Block_Queue(const int &gdefalult)
        : _capacity(gdefalult), _psleep(0), _csleep(0)
    {
        pthread_mutex_init(&_mutex, nullptr);     // 初始化锁
        pthread_cond_init(&_full_cond, nullptr);  // 初始化生产者条件变量
        pthread_cond_init(&_empty_cond, nullptr); // 初始化消费者条件变量
    }

    // 生产者
    void Equeue(const T &in)
    {
        // 加锁
        pthread_mutex_lock(&_mutex);

        // 判断队列是否为满 若满了将生产者挂起 同时释放锁
        while (Isfull())
        {
            _psleep++;                               // // 进入等待状态，休眠生产者计数增加
            pthread_cond_wait(&_full_cond, &_mutex); // 相当于解锁
            _psleep--;                               // 消费者线程调用消费函数后将生产者唤醒 此时出循环 继续生产
        }

        // 若不满 则继续生产
        _block_queue.push(in);

        // 唤醒消费者
        if (_csleep > 0)
        {
            pthread_cond_signal(&_empty_cond);
            cout << "消费者唤醒成功" << endl;
        }
        // 解锁
        pthread_mutex_unlock(&_mutex);
    }

    // 消费者
    T Pop()
    {
        // 加锁
        pthread_mutex_lock(&_mutex);
        // 判断队列是否为空
        while (Isempty())
        {
            _csleep++;
            // 挂起消费者
            pthread_cond_wait(&_empty_cond, &_mutex);
            _csleep--;
        }

        // 消费 将数据弹出队列
        T out = _block_queue.front();
        _block_queue.pop();

        // 唤醒生产者
        if (_psleep > 0)
        {
            pthread_cond_signal(&_full_cond);
            cout << "生产者唤醒成功" << endl;
        }
        // 解锁
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    ~Block_Queue()
    {
    }

private:
    std::queue<T> _block_queue; // 阻塞队列
    int _capacity;              // 队列可用容量
    pthread_mutex_t _mutex;     // 锁
    pthread_cond_t _full_cond;  // 生产者条件变量
    pthread_cond_t _empty_cond; // 消费者环境变量
    int _psleep;                // 等待队列的生产者
    int _csleep;                // 等待队列里的消费者
};